헤드리스 홉 목록을 받아 상품 문서·차단 판정을 extractor 가 맡음 - #67
Open
m-a-king wants to merge 2 commits into
Open
Conversation
- renderer 계약이 "최선의 HTML 한 장 + verdict" 에서 "거쳐 간 홉 목록(url·status·headers·body·dom)" 으로 바뀐다. 2026-09-07 prod 에이블리 공유링크 실패는 renderer 가 상품 페이지 여부를 스스로 판단하다 오판해 3KB 셸 본문을 준 것이었고, 그 판단을 이쪽으로 옮긴다 - 후보는 마지막 홉부터 거슬러 dom → body 순. 홈 피드로 튕긴 경우 상품은 앞 홉에 있고, 에이블리는 body 가 셸이고 상품은 하이드레이션된 dom 에만 있다. 구조화 데이터가 잡히는 첫 후보를 쓰고 없으면 마지막 홉 dom 으로 기존 파이프라인(셸 게이트 → LLM)을 탄다. LLM 은 한 번만 - 차단 판정(status 401·403·405·429·490, 챌린지 title)은 renderer 의 목록을 그대로 옮겨 홉 단위로 본다(HeadlessBlockSignal). 모든 홉이 차단이어야 HEADLESS_BLOCKED, 챌린지를 지나 상품 홉에 도달했으면 차단이 아니다 - 매 홉 url 을 SSRF 가드에 통과시킨다. 어느 홉이든 내부망이면 렌더 전체 거부 - renderer 배포가 수동이라 뒤처질 수 있어 구계약(html·final_url) 응답을 홉 하나로 읽는 호환을 둔다. 이 PR 을 먼저 배포한다 - 차단 status 세분화(404·410 은 상품 없음)는 infra 에러 코드 계약이 먼저라 범위 밖
|
Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- 후보 순서를 "모든 홉의 dom 을 마지막부터, 그다음 모든 홉의 body" 로 바꾼다. 앞 홉 dom 이 마지막 홉 body 보다 먼저여야 홈 피드 body 의 사이트 공통 JSON-LD 에 밀리지 않는다. body 가 dom 과 같으면 건너뛴다 - 모든 후보를 미리 파싱해 리스트로 들던 것을 루프 안 지연 파싱으로 바꾼다. 구조화 데이터가 잡히면 즉시 끝내고, 그 결과를 파이프라인 오버로드로 넘겨 같은 Document 를 두 번 파싱하지 않는다 - 차단 status 뒤에 실린 온전한 구조화 데이터는 그대로 쓴다(봇 방어는 어떤 status 로도 위장한다). 차단 신호는 LLM 후보에서만 빼고, 아무것도 못 뽑았을 때 HEADLESS_BLOCKED/UPSTREAM 을 가르는 데만 쓴다. 본문 없는 403 도 홉 단위로 차단으로 센다 - LLM fallback 은 마지막 홉 dom 이 아니라 LLM 에 넘길 것이 있는 첫 후보다. 마지막 홉이 앱 유도 셸이고 앞 홉에 텍스트가 있으면 앞 홉으로 간다 - 차단 신호에 cf-mitigated: challenge 헤더와 Cloudflare 계열 title 마커를 더한다. headers 필드가 이제 읽힌다. HeadlessBlockSignal 은 형제 분류기(EmptyShellDetector·LlmInputGate)와 같은 extraction 패키지의 package-private 으로 옮긴다 - 구계약 호환: verdict=BLOCK 은 html 이 실려 와도 HEADLESS_BLOCKED, status 만 있는 응답도 홉 하나로 읽어 차단 분류가 된다. 제거 조건(renderer #34 배포)을 주석에 남긴다 - Locale.ROOT, URL 마스킹 Pattern 상수화, 성공 로그의 항상 null 인 error 제거
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Situation
NO_EXTRACTABLE_CONTENT로 FAILED 됐다. renderer 가 3,188자 셸을 돌려줬고 셸 게이트가 그대로 확정 실패로 닫았다.Task
Action
홉 해석 (
HeadlessProductLinkExtractor)HeadlessBlockSignal). renderer 의_block_reason을 그대로 옮긴 것이고, 이제 홉 단위로 본다. 챌린지 홉을 지나 상품 홉에 도달했으면 차단이 아니다.via=structuredHEADLESS_BLOCKED(일시, 기존과 동일)HEADLESS_UPSTREAM(일시)wire (
HttpHeadlessRenderer)HeadlessRenderer가PageContent대신List<RenderedHop>을 돌려준다. 가지치기는 후보를 만들 때PageContent.of가 한다.final_url규칙과 같다).html·final_url·status) 응답은 홉 하나(dom=html)로 읽는다. renderer 가 먼저든 나중이든 배포 순서와 무관하게 동작한다.include_html을 뺐다.범위 밖
NO_EXTRACTABLE_CONTENT가 된다.Result
via=structured로 닫히는 것을 확인했다.ExtractionErrorCodeCatalogTest2건이 실패했는데 워크트리에shared-infra/카탈로그가 설치되지 않은 환경 문제다(CI 는 infra 를 체크아웃한다). 이 변경과 무관.연관 이슈